spring.jpa.show-sql=true
spring.h2.console.enabled=true
spring.datasource.url=jdbc:h2:mem:testdb
spring.jpa.defer-datasource-initialization=true
- @SpringBootApplication
- @RestController
- @AutoWired
- @RequestBody
- @PathVariable
- @ControllerAdvice
- @ExceptionHandler
- @Valid
- @Past
- @GeneratedValue
-
How are our request is handled? Dispatcher servlet - It handles root path and based on the mapping requested by browser it provides the requested link. AutoConfiguration (DispatcherServletAutoConfiguration)
-
How does bean got converted to JSON? @ResponseBody + JacksonHTTPSMessageConverter AutoConfiguration(JacksonHttpsMessageConverter)
-
Who is configuring Error Mapping? AutoConfiguration(ErrorMvcAutoConfiguration)
-
How are all the jars available? When we create starter project then we can choose what all things we want(Spring boot starter web, tomcat, jackson)
-
How exceptions are handled? ResponseEntityExceptionHandler is the class which handles the exception.
GetMapping("/somepath/{id}")
public SomeClassName function(@PathVariable("id") long id)
- GetMapping - Retrieve Details of resources
- PostMapping - create a new resources
- PutMapping - update a exisiting resources
- PatchMapping - update a part of resources
- DeleteMapping - Delete a resources
@PostMapping("/user")
public ResponseEntity<User> addUser(@RequestBody User user)
- 200 - success
- 201 - created
- 204 - No content
- 401 - Unauthorized
- 400 - Bad Request
- 404 - Resource Not Found
- 500 - Server Error
return new ResponseEntity(Object,HttpStatus.INTERNAL_SERVER_ERROR);
1. orElse() - If data is not found then we can return other.
2. if(user==null){
throw new UserNotFoundException("id:"+id);
}
@ResponseStatus(code=HttpStatus.NotFound)
class UserNotFoundException extends RuntimeException{
public UserNotFoundException(String message){
super(message);
}
}
@ResponseStatus(code=HttpStatus.NotFound)
class UserNotFoundException extends RuntimeException{
public UserNotFoundException(String message){
super(message);
}
}
public class ErrorDetails{
private LocalDate timestamp;
private String message;
private String details;
// generate getter, setters, and constructor
}
@ControllerAdvice
public class CustomizedExceptionHandler extends ResponseEntityExceptionHandler{
@ExceptionHandler(Exception.class)
public final ResponseEntity<ErrorDetails> handleAllException(Exception ex,WebRequest request){
ErrorDetails errorDetails = new ErrorDetails(LocalDate.now(),ex.getMessage(),request.getDescription(false));
return new ResponseEntity<ErrorDetails>(errorDetails,HttpStatus.INTERNAL_SERVER_ERROR);
}
@ExceptionHandler(UserNotFoundException.class)
public final ResponseEntity<ErrorDetails> handleUserNotFoundException(Exception ex,WebRequest request){
ErrorDetails errorDetails = new ErrorDetails(LocalDate.now(),ex.getMessage(),request.getDescription(false));
return new ResponseEntity<ErrorDetails>(errorDetails,HttpStatus.NOT_FOUND);
}
}
@DeleteMapping("/user/{id}")
public void deleteById(@PathVariable("id") Long id) {
userServiceImpl.deleteById(id);
}
<groupId>org.springframework.boot</groupId>
<artifactId>Spring-boot-starter-validation</artifactId>
@PostMapping(path="/addUser")
public ResponseEntity<User> addUser(@Valid @RequestBody User user){
userDao.save(user);
return new ResponseEntity<User>(user,HttpStatus.OK)
}
@Size(min=2,message="Name should be atleast 2 characters")
String name;
@Past(message="Birth date should be in past")
LocalDate date;
- Manually maintain documentation
- Generate documentation from code
- Open API - Standard language Agnostic interface, Discover and Understand Rest API
- Swagger - Visualize and Interact with your Rest API.
<!-- https://mvnrepository.com/artifact/org.springdoc/springdoc-openapi-ui -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.6.9</version>
</dependency>
Swagger Link - http://localhost:8080/swagger-ui/index.html
Open API Link - http://localhost:8080/v3/api-docs
- Same Resource and Same URI have different Representations.
- Different Content Type - XML or JSON...
- Different Language - English or Dutch...
- We can accept head to know what kind of data user expects.
- Accept Lanugage Header, Accept MIME Header etc...
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.dataformat/jackson-dataformat-xml -->
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.13.4</version>
</dependency>
good.morning.message = Good Morning
good.morning.message = Good Morning in Dutch
@GetMapping("/hello-world-I18N")
public String helloWordInternationalisation() {
Locale locale = LocaleContextHolder.getLocale();
return messageSource.getMessage("good.morning.message",null,"Default Message", locale);
}
- We can implement versioning by creating two paths ex : /v1/student and /v2/student
- We can also implement versioning with the help of params ex : /student?version=1 and /student?version=2
// Using different path
@GetMapping(path="/v1/student")
public Student version1Student() {
return new Student1("Bob Charlie");
}
@GetMapping(path="/v2/student")
public Student version2Student() {
return new Student2("Bob","Charlie");
}
// Using different Parameters (/student?version=1)
@GetMapping(path="/student",params="version=1")
public Student version1Student() {
return new Student1("Bob Charlie");
}
@GetMapping(path="/student",parms="version=2")
public Student version2Student() {
return new Student2("Bob","Charlie");
}
// Using different Header
@GetMapping(path="/student",headers ="X-API-VERSION=1")
public Student version1Student() {
return new Student("Bob Charlie");
}
@GetMapping(path="/student",headers ="X-API-VERSION=2")
public Student version2Student() {
return new Student("Bob","Charlie");
}
How to perform subsequent actions?
- We will provide data and links to perform subsequent action with the help of hateoas.
- We need to create bean with custom format and implement them.
- Use standard Implementation - HAL or Spring HATEOAS
import org.springframework.hateoas.server.mvc.WebMvcLinkBuilder;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*;
@GetMapping("/users")
public List<UserEntity> retrieveAllUsers(){
return userServiceImpl.getAll();
}
@GetMapping("/user/{id}")
public EntityModel<UserEntity> hateoasGetByID(@PathVariable("id") Long id) {
UserEntity user = userServiceImpl.getById(id).orElse(null);
EntityModel<UserEntity> entityModel = EntityModel.of(user);
WebMvcLinkBuilder link = linkTo(methodOn(this.getClass()).retrieveAllUsers());
entityModel.add(link.withRel("all-users"));
return entityModel;
}
- Change fields name - @JsonProperty("user_name")
@Column(name="name")
@JsonProperty("user_name")
private String name;
- Filtering
- Static Filtering - @JsonIgnore, @JsonIgnoreProperties (It will be added in all the URI)
@Column(name="password") @JsonIgnore private String password; or on class level also we can use @JsonIgnoreProperties({"password","dateofbirth"}) class UserEntity{ // class implementation }
- Dynamic Filtering - MappingJacksonValue, @JsonFilter with FilterProvider
- Monitoring API with Actuator
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
management.endpoints.web.exposure.include=*
http://localhost:8080/actuator/beans http://localhost:8080/actuator/env http://localhost:8080/actuator/metrics http://localhost:8080/actuator/metrics/http.server.request http://localhost:8080/actuator/mappings
To exlore the api we can use HAL Explorer
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-rest-hal-explorer</artifactId>
</dependency>
@Entity
public class Post {
@Id
int id;
@Column
(name="content")
String content;
@ManyToOne(fetch = FetchType.LAZY)
@JsonIgnore
UserEntity userEntity;
// create getter, setters, equals and hashcode methods
}
@Entity
@Table(name="USERENTITY")
public class UserEntity {
@Id
@GeneratedValue
private Long id;
@Column(name="name")
private String name;
@Column(name="date")
private String date;
@OneToMany(mappedBy="userEntity")
List<Post> posts;
// create getter, setter, equals and hashcode methods
}
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
Application.properties
spring.security.user.name=username
spring.security.user.password=password
package com.ImplementAll.security;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
import static org.springframework.security.config.Customizer.withDefaults;
@Configuration
public class SpringSecurityConfiguration {
@Bean
public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception{
// 1. All request should be authenticated
httpSecurity.authorizeHttpRequests(auth -> auth.anyRequest().authenticated());
// 2. If a request is not authenticated, a web page is shown
httpSecurity.httpBasic(withDefaults());
// 3. Disable CSRF -> POST, PUT
httpSecurity.csrf().disable();
return httpSecurity.build();
}
}
- Marker interface
- Single Valued
- Multi valued
Element Type - TYPE(class), METHOD(functions), FIELDS
MyAnno.java
@Target({ElementType.TYPE, ElementType.FIELDS})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnno {
// methods
int myValue() default 0;
}
@MyAnno(myValue = 347)
public class Demo{
}