Monday, 5 March 2018

What is use of Actuators for Spring application ?


Actuators are used to get important indicators and stats of the Spring application.
It exposes many paths, which are displayed on application start logs.

Just add dependency in pom.xml and on the application startup you will get all the available actuator URLs in the logs.

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency> 


You can see indicators in JSON format by using different paths / URLs : 
  • /beans : Displays a complete list of all the Spring beans in your application
    • All the loaded beans can be seen in application startup logs
  • /health : Shows application health information
  • /machine : Shows machine health information
  • /info : Displays arbitrary application information
  • /loggers : Shows and modifies the configuration of loggers in the application
  • /metrics : Shows 'metrics' information for the current application (like, No. of hits)
  • /mappings : Displays a collated list of all @RequestMapping paths (Exposed APIs)
  • /scheduledtasks : Displays the scheduled tasks in your application
  • /threaddump : Performs a thread dump
  • /trace : Request information, Properties from application.properties
  • /shutdown : Lets the application be gracefully shutdown
EXAMPLES
http://localhost:8080/health http://localhost:8080/loggers


Sunday, 4 March 2018

@RequestMapping vs. GetMapping


@RequestMapping is generic annotation which can define path mapping with request methods (GET/POST/PUT/DELETE etc.)

It can be applied to class and methods.
By default request method will be GET.

EXAMPLE

@Component
@RequestMapping("emp")public class EmpController {

   
   
@RequestMapping("hello")
    @ResponseBody

    public String hello() {
        return "Hello !";
    }
}

Calling URL http://localhost:8080/emp/hello will call hello method.

To define request method and path together with @RequestMapping :
@RequestMapping(path="hello", method=RequestMethod.GET)





Apart from @RequestMapping, there are several annotations specific to each request method :
  • @GetMapping
  • @PostMapping
  • @PutMapping
etc.


EXAMPLE
When exposing REST APIs, single @RequestMapping can indicate main verb and multiple methods using different annotations can indicate different operations like, get all records, get by ID, save, update etc.

@Component
@RequestMapping("emp")
public class EmpController {


    @Resource
    private EmployeeRepository employeeRepository;


    @GetMapping
    public ResponseEntity<List<Employee>> getAllEmp() {
        return ResponseEntity.ok((List<Employee>) employeeRepository.findAll());
    }

   
    @GetMapping("{id}")
    public ResponseEntity<Employee> emp(@PathVariable long id) {
        return ResponseEntity.ok(employeeRepository.findOne(id));
    }

   
    @PostMapping
    public ResponseEntity<Employee> emp(@RequestBody Employee emp) {
        return ResponseEntity.ok(employeeRepository.save(emp));
    }

   
    @PutMapping
    public ResponseEntity<Employee> emp(@PathVariable long id, @Valid @RequestBody Employee emp) {
        return ResponseEntity.ok(employeeRepository.save(emp));
    }

}


Different URLs can be used for different operations :
GET http://localhost:8080/emp

POST http://localhost:8080/emp
Request Body = { "name" : "shaan", "salary" : 12 }
Header = Content-Type : application/json


Saturday, 3 March 2018

How to make API calls using RestTemplate ?


Using RestTemplate
  • Create a service / facade class to call the API.
  • Inject new bean of RestTemplate (A Spring class) in this class using @Bean annotation.
  • Call methods : getForObject, postForObject (Best one is to use exchange method)
Below example uses a global API available on internet for getting data.


@Component
public class EmployeeService {
    @Resource
    private RestTemplate restTemplate;


    private String baseUrl = "https://jsonplaceholder.typicode.com/";
   
    @Bean
    RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
   
    public User getApiUsers() {
        User user = restTemplate.getForObject(baseUrl + "users/1", User.class);
        return user;
    }
}



Create required POJOs to hold data models
public class User {
    private Long id;
    private String name;
    private String username;
    private String email;


    // getters and setters
    // toString
}


Create Controller to inject and call the service to get API data
Used @RestController to expose API and provide request mapping
@RestController
@RequestMapping("emp")

public class EmpController {
    @Resource
    private EmployeeService employeeService;
   
    @GetMapping
    public User getUsers() {
        User user = employeeService.getApiUsers();
        System.out.println("USER : " + user);
        return user;
    }
}


How to create a Controller advice to manipulate the response from every controller ?


Define Controller advice by providing @ControllerAdvice, implement ResponseBodyAdvice and implement all the required methods.

Below example Controller advice will be called after each controller, and add the headers.

EXAMPLE
@ControllerAdvice
public class ResponseHandler implements ResponseBodyAdvice<Object> {
    @Override
    public Object beforeBodyWrite(Object arg0, MethodParameter arg1, MediaType arg2,
            Class<? extends HttpMessageConverter<?>> arg3, ServerHttpRequest arg4, ServerHttpResponse response) {
        System.out.println("Inside ResponseHandler : Contoller advice manipulating response... Adding headers !");
        response.getHeaders().add("MyHead", "Shaan");
        return response;
    }

    // Check the content type and return true, if matches

    @Override
    public boolean supports(MethodParameter arg0, Class<? extends HttpMessageConverter<?>> arg1) {
        return true;
    }
}


How to implement a global exception handler used by all the controllers ?


Create a Controller advice, which will be called on each controller.
  • Implement ResponseBodyAdvice
    (methods : beforeBodyWrite,
    supports)
    OR / AND
     
  • Implement RequestBodyAdvice
    (methods : beforeBodyRead, afterBodyRead, handleEmptyBody, supports)
supports method can be used to check proper content type and return boolean.

For a global exception handler, create a Controller advice and check request or manipulate the response.

How to use local exceptional handler in a Controller ?


Inside controller, provide specific methods for exception handling.
  • Define it using @ExceptionHandler annotation and provide exception class to handle.
  • Use exception object inside exception handler.
  • Return HTTP status and error message in response body using ResponseEntity

EXAMPLE
@Component
@RequestMapping("emp")

public class EmpController {


    @Resource
    private EmployeeRepository employeeRepository;

    @GetMapping
    public ResponseEntity<List<Employee>> getAllEmp() {
        return ResponseEntity.ok((List<Employee>) employeeRepository.findAll());
    }


    @PostMapping
    public ResponseEntity<Employee> emp(@RequestBody Employee emp) {
        return ResponseEntity.ok(employeeRepository.save(emp));
    }


    @ExceptionHandler(Exception.class)
    public ResponseEntity<String> exceptionHandler(final Exception exception) {
        System.out.println("Exception handler inside controller...");
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Invalid data");
    }

}

Whenever any of the method inside controller throws the specific exception, this exception handler will be called.

Thursday, 1 March 2018

How to use JPA and Repository with Spring application ?


Let 's suppose, we need to serve data using DB on HTTP URLs.
For this example, we are using an in-memory DB (like, H2)
  • Provide dependencies of Data JPA and H2 DB in maven config
  • Define DB properties in application.properties
  • Create a Repository for data entity by extending CrudRepository.
  • Inside controller, expose different APIs, inject this repository and call its CRUD methods

1. Add dependencies of data-jpa and h2 DB along with data-rest for exposing APIs.
        <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
        </dependency>



2. Define DB properties in application.properties
spring.datasource.url=jdbc:h2:file:~/training;DB_CLOSE_ON_EXIT=TRUE
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driver-class-name=org.h2.Driver
spring.jpa.hibernate.ddl-auto=update
spring.jpa.hibernate.show-sql=true



3. Create a POJO - Data model
@Entity
public class Employee {
    @Id
    @GeneratedValue(strategy= GenerationType.AUTO)

    private Long id;

    @NotNull
    @Size(min = 2, max = 10)
    @Column(length=60, updatable=false)

    private String name;
       
    private double salary;


    // Getters and setters
       
    @Override
    public String toString() {
        return "Employee [id=" + id + ", name=" + name + ", salary=" + salary + "]";
    }

 }


4. Create repository
public interface EmployeeRepository extends CrudRepository<Employee, Long> {
    // Optional : Customized methods

    // List<Employee> findByName(String name);
 
    // @Query("SELECT e from Employee e where e.salary=:salary")
    // List<Employee> fetchData(@Param("Salary") double salary);

}





5. Create controller and methods (exposed APIs) and access the repository
@Component
@RequestMapping("emp")

public class EmpController {

    @Resource
    private EmployeeRepository employeeRepository;
   
    @GetMapping
    public ResponseEntity<List<Employee>> getAllEmp() {
        return ResponseEntity.ok((List<Employee>) employeeRepository.findAll());
    }
   
    @GetMapping("{id}")
    public ResponseEntity<Employee> emp(@PathVariable long id) {
        return ResponseEntity.ok(employeeRepository.findOne(id));
    }
   
    @PostMapping
    public ResponseEntity<Employee> emp(@RequestBody Employee emp) {
        return ResponseEntity.ok(employeeRepository.save(emp));
    }
   
    @PutMapping
    public ResponseEntity<Employee> emp(@PathVariable long id, @Valid @RequestBody Employee emp) {
        return ResponseEntity.ok(employeeRepository.save(emp));
    }
}


 
6. Start the application and Test using Postman / RESTClient :
1. GET http://localhost:8080/emp

2. POST http://localhost:8080/emp
Request Body = { "name" : "shaan", "salary" : 12 }
Header = Content-Type : application/json