SpringBoot

Revision as of 01:07, 14 September 2018 by Rasimsen (talk | contribs) (JPA - Java Persistance API)


SpringBoot - Maven - Pom.xml

<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.oasissoftech.springboot</groupId>
	<artifactId>SpringBoot-Tutorial-1</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>SpringBoot-Tutorial-1</name>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.2.RELEASE</version>
	</parent>

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

	<properties>
		<java.version>1.8</java.version>
	</properties>

</project>

to get latest Spring Boot Starter Parent pom.xml configurations visit : https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-parent

to get latest Spring Boot Web Starter pom.xml configurations visit : https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web


SpringBoot - Application Boot

Spring Boot application startup class :

package com.oasissofttech.springboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBootTutorial1App {
	public static void main(String[] args) {
		SpringApplication.run(SpringBootTutorial1App.class,args);
	}
}


SpringBoot - Controller Class - GET, POST, PUT, DELETE

package com.oasissofttech.springboot.brand;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class BrandController {
	@Autowired
	private BrandService brandService;
	
	@RequestMapping("/brands")
	public List<Brand> getAllBrands() {
		return brandService.getAllBrands();
	}
	
	@RequestMapping("/brand/{brandId}")
	public Brand getBrand(@PathVariable("brandId") int id) {
		return brandService.getBrand(id);
	
	}
	
	@RequestMapping(method=RequestMethod.POST,value="/brands")
	public void addBrand(@RequestBody Brand brand) {
		brandService.addBrand(brand);
	}
	
	@RequestMapping(method=RequestMethod.PUT,value="/brands/{id}")
	public void addBrand(@RequestBody Brand brand,@PathVariable int id) {
		brandService.updateBrand(brand,id);
	}
	
	@RequestMapping(method=RequestMethod.DELETE,value="/brands/{id}")
	public void deleteBrand(@PathVariable int id) {
		brandService.deleteBrand(id);
	}
	
}


SpringBoot - Service Class

package com.oasissofttech.springboot.brand;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.springframework.stereotype.Service;

@Service
public class BrandService {

	private List<Brand> brands = new ArrayList<>(Arrays.asList(
			new Brand(1,"Aston Martin","(1913–present)"),
			new Brand(2,"Bentley","(1919–present)"),
			new Brand(3,"Jaguar Land Rover","(2013-present)"),
			new Brand(4,"Lotus","(1952–present)"),
			new Brand(5,"Rolls Royce","(1904–present)")
			));
	
	public List<Brand> getAllBrands(){
		return brands;
	}
	
	
	public Brand getBrand(int id) {
		return brands.stream().filter(b->b.getId()==id).findFirst().get();
	}


	public void addBrand(Brand brand) {
		brands.add(brand);
	}


	public void updateBrand(Brand brand, int id) {
		int c = brands.size();
		for(int i=0;i<c;i++) {
			if(brands.get(i).getId()==id) {
				brands.set(i, brand);
				return;
			}
		}
	}


	public void deleteBrand(int id) {
		brands.removeIf(t->t.getId()==id);
	}
	
}

Others

package com.oasissofttech.springboot.brand;

public class Brand {
	private int id;
	private String brandName;
	private String description;

	public Brand() {
	}

	public Brand(int id, String brandName, String description) {
		super();
		this.id = id;
		this.brandName = brandName;
		this.description = description;
	}


	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getBrandName() {
		return brandName;
	}

	public void setBrandName(String brandName) {
		this.brandName = brandName;
	}

	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

}

Common application properties

application.properties file

#===========================================
#=== application.properties file content ===
server.port=3000 #server HTTP port.
#===================end=====================

springboot properties file manual : https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html

JPA - Java Persistance API

ORM - Object Relational Mapping

Spring Data JPA

manual : https://docs.spring.io/spring-data/jpa/docs/current/reference/html/

Features

  • Sophisticated support to build repositories based on Spring and JPA
  • Support for Querydsl predicates and thus type-safe JPA queries
  • Transparent auditing of domain class
  • Pagination support, dynamic query execution, ability to integrate custom data access code
  • Validation of @Query annotated queries at bootstrap time
  • Support for XML based entity mapping
  • JavaConfig based repository configuration by introducing @EnableJpaRepositories.

Gradle Dependencies

dependencies {
    compile 'org.springframework.data:spring-data-jpa:2.0.10.RELEASE'
}repositories {
    maven {
        url 'https://repo.spring.io/libs-release'
    }
}


Making CRUD Operation with Repository

@Repository

import java.util.List;

import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import com.lse.library.model.Books;

@Repository
public interface LseLibraryRepository extends CrudRepository<Books,Long> {
	//ID,ISBN_NO,SUBJECT,AUTHOR,TITLE
    @Query(value="SELECT * FROM LSE_LIBRARY_BOOKS s where s.SHELF_NO = :shelfNo", nativeQuery = true) 
    List<Books> findBooksByShelfNo(@Param("shelfNo") String shelfNo);

    //LOCATION_NO
    @Query(value="SELECT * FROM LSE_LIBRARY_BOOKS s where s.ISBN_NO = :IsbnNo", nativeQuery = true) 
    Books findLocationByIsbnNo(@Param("IsbnNo") String IsbnNo);

    //STACK_NO,SHELF_NO
    @Query(value="SELECT * FROM LSE_LIBRARY_BOOKS s where s.SUBJECT like CONCAT('%',:subject,'%')", nativeQuery = true)   
    List<Books> findStacksAndShelvesBySubject(@Param("subject") String subject);

    @Query(value="SELECT count(*) ID FROM LSE_LIBRARY_BOOKS s where s.SHELF_NO = :shelfNo", nativeQuery = true) 
    int findCountOfBooksByShelfNo(@Param("shelfNo") String shelfNo);

    //SHELF_NO
    @Query(value="SELECT * FROM LSE_LIBRARY_BOOKS s where s.SUBJECT = :subject1 or s.SUBJECT = :subject2 ", nativeQuery = true)   
    List<Books> findShelvesBySubjects(@Param("subject1") String subject1,@Param("subject2") String subject2);

    //SHELF_NO
    @Query(value="SELECT * FROM LSE_LIBRARY_BOOKS s where s.SUBJECT = :subject", nativeQuery = true)   
    List<Books> findShelvesByOneSubject(@Param("subject") String subject);

}



BrandRepository interface

package com.oasissofttech.springboot.brand;

import org.springframework.data.repository.CrudRepository;

@Repository
public interface BrandRepository extends CrudRepository<Brand, Integer> {

}


BrandService Class

package com.oasissofttech.springboot.brand;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class BrandService {
	@Autowired
	private BrandRepository brandRepository;
	
	public List<Brand> getAllBrands(){
		List<Brand> brands = new ArrayList<>();
		brandRepository.findAll()
		.forEach(brands::add);
		
		return brands;
	}
	
	
	public Optional<Brand> getBrand(int id) {
		return brandRepository.findById(id);
	}


	public void addBrand(Brand brand) {
		brandRepository.save(brand);
	}


	public void updateBrand(Brand brand, int id) {
		brandRepository.save(brand);
	}


	public void deleteBrand(int id) {
		brandRepository.deleteById(id);
	}
	
}


What is WireMock?

https://www.ontestautomation.com/getting-started-with-wiremock/

From the WireMock.org website: WireMock is a flexible library for stubbing and mocking web services. Unlike general purpose mocking tools it works by creating an actual HTTP server that your code under test can connect to as it would a real web service. It supports HTTP response stubbing, request verification, proxy/intercept, record/playback of stubs and fault injection, and can be used from within a unit test or deployed into a test environment. Although it’s written in Java, there’s also a JSON API so you can use it with pretty much any language out there.

Error Handling for REST with Spring & SpringBoot

Overview

Before Spring 3.2, the two main approaches to handling exceptions in a Spring MVC application were: HandlerExceptionResolver or the @ExceptionHandler annotation. Both of these have some clear downsides.

After 3.2 we now have the new @ControllerAdvice annotation to address the limitations of the previous two solutions.


All of these do have one thing in common – they deal with the separation of concerns very well. The app can throw exception normally to indicate a failure of some kind – exceptions which will then be handled separately.

The Controller level @ExceptionHandler

The New @ControllerAdvice (Spring 3.2 And Above)

Spring 3.2 brings support for a global @ExceptionHandler with the new @ControllerAdvice annotation. This enables a mechanism that breaks away from the older MVC model and makes use of ResponseEntity along with the type safety and flexibility of @ExceptionHandler:

@ControllerAdvice
public class RestResponseEntityExceptionHandler 
  extends ResponseEntityExceptionHandler {
 
    @ExceptionHandler(value 
      = { IllegalArgumentException.class, IllegalStateException.class })
    protected ResponseEntity<Object> handleConflict(
      RuntimeException ex, WebRequest request) {
        String bodyOfResponse = "This should be application specific";
        return handleExceptionInternal(ex, bodyOfResponse, 
          new HttpHeaders(), HttpStatus.CONFLICT, request);
    }
}

The new annotation allows the multiple scattered @ExceptionHandler from before to be consolidated into a single, global error handling component.

The actual mechanism is extremely simple but also very flexible:

  • it allows full control over the body of the response as well as the status code
  • it allows mapping of several exceptions to the same method, to be handled together
  • it makes good use of the newer RESTful ResposeEntity response

One thing to keep in mind here is to match the exceptions declared with @ExceptionHandler with the exception used as the argument of the method. If these don’t match, the compiler will not complain – no reason it should, and Spring will not complain either.

However, when the exception is actually thrown at runtime, the exception resolving mechanism will fail with:

java.lang.IllegalStateException: No suitable resolver for argument [0] [type=...]
HandlerMethod details: ...


http://www.baeldung.com/exception-handling-for-rest-with-spring

Spring Boot Interview Questions and Answers